package com.hb.web;

import com.hb.data.SpittleRepository;
import com.hb.model.Spittle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Controller
@RequestMapping("/spittles")
public class SpittleController {
    private SpittleRepository spittleRepository;

    @Autowired
    public SpittleController(SpittleRepository spittleRepository) {
        this.spittleRepository = spittleRepository;
    }

    @RequestMapping(value = "/one", method = RequestMethod.GET)
    // 如果你希望使用非 Spring 类型的话，那么可以用 java.util.Map 来代替 Model。也就是 public String spittles(Map model) { ... }
    public String spittles(Model model) {
        // Model 实际上就是一个 Map（也就是 key-value 对的集合），它会传递给视图，这样数据就能渲染到客户端了。当调用 addAttribute() 方法并且不指定 key 的时候，
        // 那么 key 会根据值的对象类型推断确定。在本例中，因为它是一个 List<Spittle>，因此，键将会推断为 spittleList。
//        model.addAttribute(spittleRepository.findSpittles(Long.MAX_VALUE, 20));
        List<Spittle> list = new ArrayList<Spittle>();
        Spittle hangzhou = new Spittle("hangzhou", new Date(), 120.00, 30.00);
        Spittle beijing = new Spittle("beijing", new Date(), 116.00, 40.00);
        list.add(hangzhou);
        list.add(beijing);
        model.addAttribute(list);
        return "spittles";
    }

    // 这个版本与其他的版本有些差别。它并没有返回视图名称，也没有显式地设定模型，这个方法返回的是 Spittle 列表。当处理器方法像这样返回对象或集合时，
    // 这个值会放到模型中，模型的 key 会根据其类型推断得出（在本例中，也就是spittleList）。而逻辑视图的名称将会根据请求路径推断得出。因为这个方法处理针
    // 对 “/spittles” 的 GET 请求，因此视图的名称将会是 spittles（去掉开头的斜线）。
    @RequestMapping(value = "/two", method = RequestMethod.GET)
    public List<Spittle> spittles() {
        return spittleRepository.findSpittles(Long.MAX_VALUE, 20);
    }

    // 不管你选择哪种方式来编写 spittles() 方法，所达成的结果都是相同的。模型中会存储一个 Spittle 列表，key 为 spittleList，然后这个列表会发送到名为 spittles 的视图中。
    // 按照我们配置 InternalResourceViewResolver 的方式，视图的 JSP 将会是 “/WEB-INF/views/spittles.jsp”。

    // SpringMVC 允许以多种方式将客户端中的数据传送到控制器的处理器方法中，包括：1、查询参数；2、表单参数；3、路径变量。

    private static final String MAX_LONG_AS_STRING = "9223372036854775807";

    /**
     * 处理查询参数的形式，同时使用了默认值 Long.MAX_VALUE 和 20 兼并了上面的方法。
     * 因为查询参数都是 String 类型的，因此 defaultValue 属性需要 String 类型的值。
     *
     * @param max
     * @param count
     * @return
     */
    @RequestMapping(value = "/three", method = RequestMethod.GET)
    public List<Spittle> spittles(
            @RequestParam(value = "max", defaultValue = MAX_LONG_AS_STRING) long max,
            @RequestParam(value = "count", defaultValue = "20") int count) {
        return spittleRepository.findSpittles(max, count);
    }

    /**
     * SpringMVC 允许我们在 @RequestMapping 路径中添加占位符。占位符的名称要用大括号（“{”和“}”）括起来。路径中的其他部分要与所处理的请求完全匹配，
     * 但是占位符部分可以是任意的值。下面的处理器方法使用了占位符，将 Spittle ID 作为路径的一部分。这样就能够处理针对“/spittles/12345”的请求。
     *
     * @return
     */
    @RequestMapping(value = "/{spittleId}", method = RequestMethod.GET)
    // 如果 @PathVariable 中没有 value 属性的话，它会假设占位符的名称与方法的参数名（形参）相同。这能够让代码稍微简洁一些，因为不必重复
    // 写占位符的名称了。但需要注意的是，如果你想要重命名参数时，必须要同时修改占位符的名称，使其互相匹配。
    public String spittle(@PathVariable("spittleId") long spittleId, Model model) {
        model.addAttribute(spittleRepository.findOne(spittleId));
        return "spittle";
    }
}
